package core.sim.elfarol;

import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.*;

import stats.*;
import utility.*;
import core.*;
import core.genetic.*;
import core.neural.*;
import core.sim.*;

public class AdvancedSparseSim implements SingleSimulation {
	
	@Override
	public int getSurroungingsCount() {
		return 0;
	}

	@Override
	public int getInfluencesCount() {
		return 1;
	}

	@Override
	public int getInputCounts() {
		return 1 + Mode.mode.FEROMONS + Mode.mode.MEMORY;
	}

	@Override
	public int getOutputCounts() {
		return getInfluencesCount() + Mode.mode.FEROMONS + Mode.mode.MEMORY;
	}

	private int turns;
	private final boolean diffOutputs;

	public AdvancedSparseSim(int turns, boolean diffOutputs) {
		this.turns = turns;
		this.diffOutputs = diffOutputs;
	}

	@Override
	public double[] playSimulation(Individual[] individuals) {
		int n = individuals.length;
		double[][] feromons = new double[n][Mode.mode.brain.FEROMONS];
		double[][] memory = new double[n][Mode.mode.brain.MEMORY];

		double[][] outputs = new double[n][];
		double[][] inputs = new double[n][];

		for (int i = 0; i <= turns; i++) {
			for (int j = 0; j < n; j++)
			{
				inputs[j] = BrainParsing.mergeInputs(new double[0],	feromons[j], memory[j]);
				outputs[j] = Mode.mode.brain.calculateOutputs(individuals[j], inputs[j] );
			}
			if (i < turns) {
				for (int j = 0; j < n; j++)
					for (int k = 0; k < Mode.mode.brain.FEROMONS; k++)
						feromons[j][k] = 0;

				for (int j = 0; j < n; j++) {
					double[][] splitted = BrainParsing.splitOutput(outputs[j]);
					System.arraycopy(splitted[BrainParsing.MEMORY_POS], 0, memory[j], 0, Mode.mode.brain.MEMORY);
					for (int k = 0; k < n; k++)
						if (j != k) {
							for (int t = 0; t < Mode.mode.brain.FEROMONS; t++)
								feromons[k][t] += splitted[BrainParsing.FEROMONS_POS][t];
						}
				}
			}
		}
		
		double MIN = -1;
		double MAX = 1;

		Pair<Double, Integer>[] guesses = (Pair<Double, Integer>[])new Pair<?, ?>[n+2];
		for (int i = 0; i < n; i++)
			guesses[i] = new Pair<Double, Integer>(Math.max(MIN, Math.min(MAX, outputs[i][0])),i);
		guesses[n] = new Pair<Double, Integer>(MIN, -1);
		guesses[n+1] = new Pair<Double, Integer>(MAX,-1);
		
		// System.out.print(Arrays.toString(guesses));
		
		Arrays.sort(guesses, new Pair.FirstComparator<Double,Integer>());
		
		// System.out.println(" - " + Arrays.toString(guesses));
		double[] res = new double[n];		
		if (diffOutputs) 
		{
			for(int i = 0; i < n+2; i++) {				
				int k = guesses[i].second();
				if (k>=0) {
					int j = Math.min(n, Math.max(1, i));
					res[k] = Math.min(guesses[j + 1].first() - guesses[j].first(), guesses[j].first() - guesses[j-1].first());
					Statistics.addTeamResult(res[k]);		
				}
			}
//			System.out.println(Arrays.toString(guesses) + "\t\t" + Arrays.toString(res) + "\t\t" + Arrays.toString(individuals) + "\t\t" + Arrays.toString(inputs[0]));
//			System.out.flush();
		}
		else 
		{
			double max = Double.POSITIVE_INFINITY;
			for (int i = 0; i + 1 < n+2; i++)
				max = Math.min(max, guesses[i + 1].first() - guesses[i].first());

			Statistics.addTeamResult(max);		
			for (int i = 0; i < n; i++)
				res[i] = max;
			
//			System.out.println(Arrays.toString(guesses) + "\t\t" + Arrays.toString(res) + "\t\t" + Arrays.toString(individuals) + "\t\t" + Arrays.toString(inputs[0]));

		}
		
		return res;
	}

	@Override
	public void drawSimulation(Population pop, double[] values) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void drawMovie(Graphics2D g2, Point2D dim) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void executeForMovie(Individual[] individuals) {
		// TODO Auto-generated method stub
		
	}

}
